package es.geoorge.hundirlaflota;

import java.util.Iterator;

import android.app.Activity;
import android.content.Context;
import android.graphics.Bitmap;
import android.graphics.BitmapFactory;
import android.graphics.Canvas;
import android.graphics.Color;
import android.graphics.Paint;
import android.graphics.Rect;
import android.graphics.Typeface;
import android.view.*;
import android.widget.Toast;
/**
 * Esta clase es la encargada de la generacion de los tableros, de manera manual y grafica en caso de que sean jugadores y automatica en caso de que sea el de la Maquina.
 * Tambien es la que vamos a visualizar durante la partida y se encargara de dibujar el tablero correspondiente a cada turno.
 * @author Georthik
 * @version x.x
 */
public class mView extends View {
	Mensajero mens;
	Activity act;
	Casilla matCasillas[][] = new Casilla[10][10];
	Barco arrBarcos[] = new Barco[5];
	Context con = null;
	Barco barcoDibujado;
	float scale = 0;
	Paint whitePaint;
	int ancho = 0;
	int alto = 0;
	int matriz[][] = new int[10][10];
	int matrizAux[][] = new int[10][10];
	Rect btnGirar;
	int yMaxTabla=0;
	int yLibre=0;
	int margen=0;
	int yBarco=0;
	int casillax;
	int casillay;
	int casillaxAux=11;
	int casillayAux=11;
	int anchocua = 0;
	int moviendox;
	int moviendoy;
	boolean fdraw = true;
	boolean fdrawJugando = true;
	boolean cambios = false;
	boolean barcoPuesto = false;
	int barcoMoviendo = 0;
	boolean moviendoBarco = false;
	boolean enCuadricula = false;
	boolean error = false;
	boolean jugando=false;
	boolean orientacion = true;
	int contadorBarcosPuestos = 0;
	private int barcosMaquinaHundidos;
	private Toast toast;
	private int duracion=Toast.LENGTH_SHORT;
	private Bitmap tempBitmap;
	private Bitmap scaledBitmap;
	private int scaledCardW;
	private int resourceId;
	private int scaledCardH;

	/**
	 * Constructor para la generacion de un "tablero" manual, inicializa las matrices numericas y crea un paint auxiliar para obtener la escala de la pantalla.
	 * @param actividad actividad actual.
	 * @param mens la clase intermediaria, el Mensajero.
	 */
	public mView(Activity actividad,Mensajero mens) {
		super(actividad.getApplicationContext());
		Paint whitePaint;
		act=actividad;
		con = act.getApplicationContext();
		this.mens=mens;
		setKeepScreenOn(true);
		scale = con.getResources().getDisplayMetrics().density;
		whitePaint = new Paint();
		whitePaint.setAntiAlias(true);
		whitePaint.setColor(Color.WHITE);
		whitePaint.setStyle(Paint.Style.STROKE);
		whitePaint.setTextAlign(Paint.Align.LEFT);
		whitePaint.setTextSize(scale * 15);
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				matriz[i][j] = 0;
				matrizAux[i][j] = 0;
			}
		}
	}
	
	/**
	 * Constructor para la generacion automatica del "tablero" de la maquina, genera de manera aleatoria la colocacion de los barcos respetando los espacios de agua marcados en las reglas.
	 * @param actividad la actividad actual.
	 * @param mens la clase intermediaria.
	 * @param maquina este parametro sirve unicamente para diferenciar el constructor manual del automatico, no importa su valor.
	 */
	public mView(Activity actividad, Mensajero mens,boolean maquina) {
		super(actividad.getApplicationContext());
		Paint whitePaint;
		act=actividad;
		con = act.getApplicationContext();
		this.mens=mens;
		scale = con.getResources().getDisplayMetrics().density;
		whitePaint = new Paint();
		whitePaint.setAntiAlias(true);
		whitePaint.setColor(Color.WHITE);
		whitePaint.setStyle(Paint.Style.STROKE);
		whitePaint.setTextAlign(Paint.Align.LEFT);
		whitePaint.setTextSize(scale * 15);
		for (int i = 0; i < 10; i++) {
			for (int j = 0; j < 10; j++) {
				matriz[i][j] = 0;
				matrizAux[i][j] = 0;
			}
		}

		do{
			Barco bAux=null;
			do{
				error=false;
				int x=(int)(Math.random()*10);
				int y=(int)(Math.random()*10);
				int direccion=(int)(Math.random()*4);
				if(direccion%2==0){
					orientacion=!orientacion;
				}
				try{
					bAux=new Barco(x,y,orientacion,getLongitud(),matriz,contadorBarcosPuestos+1);
				}catch(Exception exc){
					error=true;
					for(int j=0;j<10;j++){
						for(int k=0;k<10;k++){
							matriz[j][k]=matrizAux[j][k];
						}
					}
				}
			}while(error);
			arrBarcos[contadorBarcosPuestos]=bAux;
			contadorBarcosPuestos++;
			for(int j=0;j<10;j++){
				for(int k=0;k<10;k++){
					matrizAux[j][k]=matriz[j][k];
				}
			}
		}while(contadorBarcosPuestos<5);
		mens.enviarTabMaquina(this);
	}


	/**
	 * Es el metodo encargado de dibujar la pantalla la primera vez que se ejecuta esta vista y cada vez que se interactua con ella.
	 * Es donde se trata la generacion manual del "tablero" de juego. dibuja la matriz de casillas que componen el tablero, un boton para seleccionar la orientacion del barco a colocar,
	 * el cuerpo del barco a colocar que se colocara mediante arrastre del mismo y un texto indicando la orientacion actual del barco. Maneja las comprobaciones necesarias para
	 * que los barcos colocados esten dentro de la cuadricula del tablero y no se superpongan a otros barcos. Tambien obliga a respetar el espacio minimo entre barcos.
	 * Una vez empieza la partida realiza las transiciones de tableros segun el turno actual.
	 * @Override	
	 */
	protected void onDraw(Canvas canvas) {
		canvas.drawRGB(0, 0, 0);
		ancho = canvas.getWidth();
		alto = canvas.getHeight();
		anchocua = ancho / 10;
		Paint paint = new Paint();
		paint.setTextSize(20);
		Paint paint2 = new Paint();
		paint2.setTextSize(17);
		paint2.setTypeface(Typeface.DEFAULT_BOLD);
		paint2.setARGB(255, 255,255,255);
		Paint paintlinea1 = new Paint();
		paintlinea1.setARGB(255, 255, 255, 255);
// si no se esta jugando se esta en la fase de creacion del tablero, es decir, colocando los barcos.
		if(!jugando){
			int filaact = 0;
			if(fdraw){
				moviendox=ancho;
				moviendoy=alto;
				fdraw=false;
			}
			for (int f = 0; f < 10; f++) {
				for (int c = 0; c < 10; c++) {
					Casilla aux = new Casilla(c * anchocua, filaact, anchocua);
					matCasillas[f][c] = aux;
					paint.setARGB(153, 204, 204, 204);
					canvas.drawRect(c * anchocua, filaact, c * anchocua + anchocua- 2, filaact + anchocua - 2, paint);
					canvas.drawLine(c * anchocua, filaact, c * anchocua + anchocua,filaact, paintlinea1);
					canvas.drawLine(c * anchocua + anchocua - 1, filaact, c* anchocua + anchocua - 1, filaact + anchocua,paintlinea1);
				}
				filaact = filaact + anchocua;
			}
			yMaxTabla = matCasillas[9][0].getY() + anchocua;
			yLibre = alto - yMaxTabla;
			margen = anchocua - (int) (anchocua / 2);
			yBarco = alto - yLibre + margen;
			// Boton de girar el barco
//			paint.setARGB(250, 200, 50, 200);
			btnGirar = new Rect(margen, yBarco, anchocua* 2, yBarco+ anchocua*2);
//			canvas.drawRect(btnGirar, paint);
			tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.girar);
			scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, anchocua*2, anchocua*2, false);
			canvas.drawBitmap(scaledBitmap,margen, yBarco , paint);
			// barco
	
			barcoDibujado = new Barco(margen * 5 + anchocua, yBarco, anchocua,getLongitud());
//			paint.setARGB(215, 50, 200, 50);
			resourceId = getResources().getIdentifier("barco" +getLongitud(), "drawable", con.getPackageName());
			tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
	        scaledCardW = (int) anchocua*getLongitud();
	        scaledCardH = anchocua;
	        try{
			scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false);
			canvas.drawBitmap(scaledBitmap, margen * 5 + anchocua, yBarco, paintlinea1);
	        }catch(Exception e){}
//			canvas.drawRect(margen * 3 + anchocua, yBarco, (margen * 3 + anchocua)+ anchocua * getLongitud(), yBarco + anchocua, paint);
			
			// orientacion
			if(orientacion){
				canvas.drawText("Posicion: Horizontal", margen, (float) (yBarco+anchocua*1.5+margen*2), paint2);
			}else{
				canvas.drawText("Posicion: Vertical", margen, (float) (yBarco+anchocua*1.5+margen*2), paint2);
			}
			if (moviendoBarco) {
				if(casillax!=casillaxAux || casillay!=casillayAux){
					for (int i = 0; i < 10; i++) {
						for (int j = 0; j < 10; j++) {
							matriz[i][j] = matrizAux[i][j];
						}
					}
					error = false;
					//aqui se prueba a crear un barco en la posicion actual, si da error es porque no cumple con las reglas del juego y se muestra en rojo el barco.
					try {
						Barco movAux = new Barco(casillax, casillay, orientacion,getLongitud(), matriz, contadorBarcosPuestos + 1);
	
					} catch (Exception e) {
						error = true;					
					}
				}
				String sufijo="";
				if(!error){
						sufijo="r";
					}else{
						sufijo="w";
					}
					if (orientacion) {
						resourceId = getResources().getIdentifier("barco" +getLongitud()+sufijo, "drawable", con.getPackageName());
				        scaledCardW = (int) anchocua*getLongitud();
				        scaledCardH = anchocua;
					} else {
						resourceId = getResources().getIdentifier("barco" +getLongitud()+"v"+sufijo, "drawable", con.getPackageName());
				        scaledCardW = anchocua;
				        scaledCardH = (int) anchocua*getLongitud();						
					}
					tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
					scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false); 
					canvas.drawBitmap(scaledBitmap, moviendox, moviendoy, paint);
					casillaxAux=casillax;
					casillayAux=casillay;
			}
			if (barcoPuesto) {
				contadorBarcosPuestos--;
				arrBarcos[contadorBarcosPuestos] = new Barco(casillax, casillay,moviendox, moviendoy, orientacion, getLongitud(), matriz,contadorBarcosPuestos + 1);
				contadorBarcosPuestos++;
				barcoPuesto = false;
				for (int i = 0; i < 10; i++) {
					for (int j = 0; j < 10; j++) {
						matrizAux[i][j] = matriz[i][j];
					}
				}
				if(contadorBarcosPuestos==5){
	  				jugando=true;
					mens.enviarTabJugador(this);
					invalidate();
				}
			}
			
			try {
				paint.setARGB(255, 235, 195, 30);
				for (int i = 0; i < 5; i++) {
					if (arrBarcos[i].getOrientacion()) {
						resourceId = getResources().getIdentifier("barco" + arrBarcos[i].getLongitud(), "drawable", con.getPackageName());
						tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
				        scaledCardW = (int) anchocua*arrBarcos[i].getLongitud();
				        scaledCardH = anchocua;
						scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false); 
						canvas.drawBitmap(scaledBitmap, arrBarcos[i].getX(),arrBarcos[i].getY(), paint);
					} else {
						resourceId = getResources().getIdentifier("barco" + arrBarcos[i].getLongitud()+"v", "drawable", con.getPackageName());
						tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
						scaledCardH = (int) anchocua*arrBarcos[i].getLongitud();
				        scaledCardW = anchocua;
						scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false); 
						canvas.drawBitmap(scaledBitmap, arrBarcos[i].getX(),arrBarcos[i].getY(), paint);
					}
				}
			} catch (Exception e) {}
		}else{
			//fdraw inicializa la matriz de la vista de la maquina.
			int filaact = 0;
			if(fdrawJugando){
				for (int f = 0; f < 10; f++) {
					for (int c = 0; c < 10; c++) {
						Casilla aux = new Casilla(c * anchocua, filaact, anchocua);
						mens.tableroMaquina.matCasillas[f][c] = aux;
					}
					filaact = filaact + anchocua;
				}
				fdrawJugando=false;
			}
			filaact=0;
			//en el turno del jugador se juega sobre la vista de la cuadricula de la maquina
			if(mens.turnoJugador){			
				for (int f = 0; f < 10; f++) {
					for (int c = 0; c < 10; c++) {
						if (!mens.tableroMaquina.matCasillas[f][c].isDestapado()){
							paint.setARGB(153, 204, 204, 204);
							canvas.drawRect(c * anchocua, filaact, c * anchocua + anchocua- 2, filaact + anchocua - 2, paint);
						}else if(mens.tableroMaquina.matCasillas[f][c].getAgua()){
							tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.ic_agua);
							scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, anchocua, anchocua, false); 
							canvas.drawBitmap(scaledBitmap,c * anchocua, filaact, paint);
						}else{
							tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.ic_explosion);
							scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, anchocua, anchocua, false); 
							canvas.drawBitmap(scaledBitmap,c * anchocua, filaact, paint);
						}
						canvas.drawLine(c * anchocua, filaact, c * anchocua + anchocua,filaact, paintlinea1);
						canvas.drawLine(c * anchocua + anchocua - 1, filaact, c* anchocua + anchocua - 1, filaact + anchocua,paintlinea1);
					}
					filaact = filaact + anchocua;
				}
			//en el turno de la maquina se ve la vista de la cuadricula del jugador
			}else{
				//se dibujan los barcos del jugador
				for (int i = 0; i < 5; i++) {
					if (mens.tableroJugador.arrBarcos[i].getOrientacion()) {
						resourceId = getResources().getIdentifier("barco" + mens.tableroJugador.arrBarcos[i].getLongitud(), "drawable", con.getPackageName());
						tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
				        scaledCardW = (int) anchocua*mens.tableroJugador.arrBarcos[i].getLongitud();
				        scaledCardH = anchocua;
						scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false); 
						canvas.drawBitmap(scaledBitmap, mens.tableroJugador.arrBarcos[i].getX(),mens.tableroJugador.arrBarcos[i].getY(), paint);
					} else {
						resourceId = getResources().getIdentifier("barco" + mens.tableroJugador.arrBarcos[i].getLongitud()+"v", "drawable", con.getPackageName());
						tempBitmap = BitmapFactory.decodeResource(con.getResources(), resourceId);
						scaledCardH = (int) anchocua*mens.tableroJugador.arrBarcos[i].getLongitud();
				        scaledCardW = anchocua;
						scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, scaledCardW, scaledCardH, false); 
						canvas.drawBitmap(scaledBitmap, mens.tableroJugador.arrBarcos[i].getX(),mens.tableroJugador.arrBarcos[i].getY(), paint);
					}
				}
				for (int f = 0; f < 10; f++) {
					for (int c = 0; c < 10; c++) {
						if (!mens.tableroJugador.matCasillas[f][c].isDestapado()){
							paint.setARGB(153, 204, 204, 204);
							canvas.drawRect(c * anchocua, filaact, c * anchocua + anchocua- 2, filaact + anchocua - 2, paint);
						}else if(mens.tableroJugador.matCasillas[f][c].getAgua()){
							tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.ic_agua);
							scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, anchocua, anchocua, false); 
							canvas.drawBitmap(scaledBitmap,c * anchocua, filaact, paint);
						}else{
							tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.ic_explosion);
							scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, anchocua, anchocua, false); 
							canvas.drawBitmap(scaledBitmap,c * anchocua, filaact, paint);
						}
						canvas.drawLine(c * anchocua, filaact, c * anchocua + anchocua,filaact, paintlinea1);
						canvas.drawLine(c * anchocua + anchocua - 1, filaact, c* anchocua + anchocua - 1, filaact + anchocua,paintlinea1);
					}
					filaact = filaact + anchocua;
				}
			}
			int barcosJugadorHundidos=0;
			for(int z=0;z<5;z++){
				if(mens.tableroJugador.arrBarcos[z].estaHundido()){
					barcosJugadorHundidos++;
				}
			}
			tempBitmap = BitmapFactory.decodeResource(con.getResources(), R.drawable.panel);
			scaledBitmap = Bitmap.createScaledBitmap(tempBitmap, ancho, yLibre, false); 
			canvas.drawBitmap(scaledBitmap,0,yBarco-margen, paint);
			paint2.setARGB(250,250,250,250);
			canvas.drawText("Jugador "+(5-barcosJugadorHundidos)+"/5", margen, yBarco+margen, paint2);
			canvas.drawText("Maquina: "+(5-barcosMaquinaHundidos)+"/5", ancho/2+margen, yBarco+margen, paint2);
		}
	}

	/**
	 * Es el metodo encargado de la interaccion con la pantalla. Es utilizado para reconocer cuando se ha tocado dentro de la superficie de un barco, cuando se esta moviendo y cuando se suelta para su posterior colocacion
	 * Tambien controla la interaccion con el boton de girar los barcos. Y una vez ha empezado la partida se encarga de la comprobacion de las coordenadas elegidas por el jugador.
	 * @Override 
	 */
	public synchronized boolean onTouchEvent(MotionEvent me) {
		int eventaction = me.getAction();
		int x = (int) me.getX();
		int y = (int) me.getY();
		switch (eventaction) {
		case MotionEvent.ACTION_DOWN:
			if(!jugando){
				if (barcoDibujado.dentro(x, y)) {
					moviendoBarco = true;
				}
				if (btnGirar.contains(x, y)) {
					orientacion = !orientacion;
				}
			}else{
				mens.sound.play(mens.disparo);
				if(mens.turnoJugador){
					for (int i = 0; i < 10; i++) {
						for (int j = 0; j < 10; j++) {
							if (mens.tableroMaquina.matCasillas[i][j].dentro(x, y)&&!mens.tableroMaquina.matCasillas[i][j].isDestapado()) {
								mens.tableroMaquina.matCasillas[i][j].destapar();
								switch(mens.tableroMaquina.probarCoor(i,j)){
									case 0:
										mens.sound.play(mens.agua);
										mens.tableroMaquina.matCasillas[i][j].setAgua(true);
										invalidate();
										mens.jugadorOnAgua();
									break;
									case 1: mens.sound.play(mens.tocado);;break;
									case 2: mens.sound.play(mens.tocado);	
										toast = Toast.makeText(con, "HUNDIDO", duracion);
									toast.show();
									barcosMaquinaHundidos++;
									break;
								}								
								i=9;j=9;
							}
						}
					}
					if(barcosMaquinaHundidos>=5){
						mens.ganaElJugador();
					}
				}
				invalidate();
			}
			break;
		case MotionEvent.ACTION_MOVE:
			if(!jugando){
				if (moviendoBarco) {
					moviendoy = (int) (y - anchocua / 0.8);
					if (x > ancho / 2) {
						moviendox = (int) (x + anchocua / 1.2);
					} else {
						moviendox = (int) (x - (anchocua / 1.2));
					}
					for (int i = 0; i < 10; i++) {
						for (int j = 0; j < 10; j++) {
							if (matCasillas[i][j].dentro(moviendox, moviendoy)) {
								moviendox = matCasillas[i][j].getX();
								moviendoy = matCasillas[i][j].getY();
								casillax = i;
								casillay = j;
								i = 9;
								j = 9;
								enCuadricula = true;
							} else {
								enCuadricula = false;
							}
						}
					}
				}
			}
			break;
		case MotionEvent.ACTION_UP:
			if(!jugando){
				if (moviendoBarco) {
					if (enCuadricula && !error) {
						barcoPuesto = true;
						contadorBarcosPuestos++;
						enCuadricula = false;
					}
					moviendoBarco = false;
				}
				break;
			}
		}
		invalidate();
		return true;
	}

	/**
	 * Devuelve la longitud a tener en cuenta segun el barco actual, los barcos se colocaran por orden empezando por el mas pequeno y acabando por el mayor.
	 * @return
	 */
	public int getLongitud() {
		int longitud = 0;
		switch (contadorBarcosPuestos) {
		case 0:
			longitud = 2;
			break;
		case 1:
		case 2:
			longitud = 3;
			break;
		case 3:
			longitud = 4;
			break;
		case 4:
			longitud = 5;
			break;
		}
		return longitud;
	}

	/**
	 * Este metodo se encarga de comprobar el contenido de la matriz numerica basandose en las coordenadas recibidas.
	 * @param x 
	 * @param y
	 * @return devuelve 0 en caso de que sea agua, 1 si se ha tocado algun barco y 2 si se ha hundido dicho barco. 
	 */
	public synchronized int probarCoor(int x, int y){	
		int num=-1;
		if(matriz[x][y]==0||matriz[x][y]==9){
			matCasillas[x][y].setAgua(true);
			num=0;//agua
		}else{
			int i=matriz[x][y]-1;
			arrBarcos[i].tocado();
			num=1;//tocado
			if(arrBarcos[i].estaHundido()){
				num=2;//hundido
			}
		}
		return num;
	}
	
	/**
	 * cuando un barco es tocado, el metodo de la clase Barco que responde a este evento se encarga de convertir su valor en la matriz numerica a 0. Por lo tanto cuando toda la matriz numerica
	 * esta compuesta de 9 o 0 (ambos casos corresponden a "agua") se ha finalizado el juego.
	 * @return
	 */
	public boolean finJuego(){
		for(int i=0;i<10;i++){
			for(int j=0;j<10;j++){
				if(matriz[i][j]!=0&&matriz[i][j]!=9){
					return false;
				}
			}
		}
		return true;
	}
}
